package top.xia17.plugins.demo.security;

import org.springframework.security.web.SecurityFilterChain;
import top.xia17.plugins.fast.common.security.HttpStatusAccessDeniedHandler;
import top.xia17.plugins.fast.common.security.HttpStatusAuthenticationEntryPoint;
import top.xia17.plugins.fast.common.security.anonymous.AnonymousRequestPathStore;
import top.xia17.plugins.fast.common.autoconfiguration.TokenProperties;
import top.xia17.plugins.fast.common.security.token.provider.TokenProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import top.xia17.plugins.fast.auth.security.TokenSecurityConfigurer;

/**
 * 安全框架Security配置
 *
 * @author xia17
 * @date 2021/6/23 17:28
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
@RequiredArgsConstructor
public class SecurityConfig {

    private final TokenProvider tokenProvider;
    private final TokenProperties tokenProperties;
    private final AnonymousRequestPathStore anonymousRequestPathStore;


    /**
     * 配置url 拦截
     *
     * @param http HttpSecurity
     * @throws Exception 异常
     */
    @Bean
    protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http.apply(new TokenSecurityConfigurer(tokenProvider, tokenProperties));

        http
                // 禁用 CSRF
                .csrf().disable()
                .cors().disable()
                // 不创建会话。
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // 添加授权异常
                .exceptionHandling()
                .accessDeniedHandler(new HttpStatusAccessDeniedHandler())
                .authenticationEntryPoint(new HttpStatusAuthenticationEntryPoint())
                .and()
        ;

        // 资源保护
        http.authorizeRequests()
                .antMatchers("/test/**").permitAll()
                .antMatchers("/auth").permitAll()
                .antMatchers("/druid/**").permitAll()
                .antMatchers("/datasource/**").permitAll()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                // 自定义匿名访问所有url放行：允许匿名和带Token访问，细腻化到每个 Request 类型
                // GET
                .antMatchers(HttpMethod.GET, anonymousRequestPathStore.getGetPaths().toArray(new String[0])).permitAll()
                // POST
                .antMatchers(HttpMethod.POST, anonymousRequestPathStore.getPostPaths().toArray(new String[0])).permitAll()
                // PUT
                .antMatchers(HttpMethod.PUT, anonymousRequestPathStore.getPutPaths().toArray(new String[0])).permitAll()
                // PATCH
                .antMatchers(HttpMethod.PATCH, anonymousRequestPathStore.getPatchPaths().toArray(new String[0])).permitAll()
                // DELETE
                .antMatchers(HttpMethod.DELETE, anonymousRequestPathStore.getDeletePaths().toArray(new String[0])).permitAll()
                // 所有类型的接口都放行
                .antMatchers(anonymousRequestPathStore.getAllPaths().toArray(new String[0])).permitAll()
                .anyRequest().authenticated();

        return http.build();
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}
